package com.five.monkey.feign.provider.lock.zk;

import com.five.monkey.feign.provider.lock.Lock;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * zk分布式可重入锁
 * @author 狻猊
 * @date 2021/10/9 10:58 上午
 */
public class ZkLock implements Lock {

    private static final Logger logger = LoggerFactory.getLogger(ZkLock.class);

    private final InterProcessMutex interProcessMutex;

    public ZkLock(InterProcessMutex interProcessMutex) {
        this.interProcessMutex = interProcessMutex;
    }

    /**
     * 无限等待直到获得锁
     * @return true:加锁成功; false:加锁失败
     */
    @Override
    public boolean acquire() {
        boolean flag = false;
        try {
            this.interProcessMutex.acquire();
            flag = true;
        } catch (Exception e) {
            logger.error("zk分布式锁加锁失败", e);
        }
        return flag;
    }

    /**
     * 在time时间内没有获得锁，则认为加锁失败
     * @param time 加锁超时时间
     * @param unit 时间单位
     * @return true:加锁成功; false:加锁失败
     */
    @Override
    public boolean acquire(Long time, TimeUnit unit) {
        if (Objects.isNull(time) || time.compareTo(0L) <= 0) {
            throw new IllegalArgumentException("time传值错误,time不能为null且必须大于0");
        }
        if (Objects.isNull(unit)) {
            throw new IllegalArgumentException("unit传值错误,unit不能为null");
        }

        boolean flag = false;
        try {
            flag = this.interProcessMutex.acquire(time, unit);
        } catch (Exception e) {
            logger.error("zk分布式锁加锁失败", e);
        }
        return flag;
    }

    /**
     * 获得锁失败即认为加锁失败，无需等待其他线程释放锁
     * @return true:加锁成功; false:加锁失败
     */
    @Override
    public boolean acquireNotWait() {
        boolean flag = false;
        try {
            flag = this.interProcessMutex.acquire(-1, TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            logger.error("zk分布式锁加锁失败", e);
        }
        return flag;
    }

    /**
     * 释放锁
     * @return true:释放锁成功; false:释放锁失败
     */
    @Override
    public boolean release() {
        boolean flag = false;
        try {
            this.interProcessMutex.release();
            flag = true;
        } catch (IllegalMonitorStateException e) {
            logger.info("未获得锁,无需释放");
        } catch (Exception e) {
            logger.error("zk分布式锁释放锁失败", e);
        }
        return flag;
    }
}
